package web.suzy.oj.manager.admin.account;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import web.suzy.oj.common.exception.StatusAccessDeniedException;
import web.suzy.oj.common.exception.StatusFailException;
import web.suzy.oj.dao.user.SessionEntityService;
import web.suzy.oj.dao.user.SysUserRoleEntityService;
import web.suzy.oj.pojo.dto.LoginDTO;
import web.suzy.oj.pojo.entity.user.Session;
import web.suzy.oj.pojo.entity.user.SysRole;
import web.suzy.oj.pojo.vo.SysUserRoleVO;
import web.suzy.oj.pojo.vo.UserInfoVO;
import web.suzy.oj.shiro.AccountProfile;
import web.suzy.oj.utils.Constants;
import web.suzy.oj.utils.IpUtils;
import web.suzy.oj.utils.JwtUtils;
import web.suzy.oj.utils.RedisUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * YangSuzy 软件工作室
 * 类名: AdminAccountManager
 * 描述: ---- 待定 -----
 * 功能: 处理管理员账户登录登出
 *
 * @author YangSuzy
 * Date: 2022/11/17 16:05
 */
@Component
public class AdminAccountManager {

    @Autowired
    private SessionEntityService sessionEntityService;

    @Autowired
    private JwtUtils jwtUtils;

    @Resource
    private RedisUtils redisUtils;

    @Autowired
    private SysUserRoleEntityService userRoleEntityService;

    /**
     * 方法名: login
     * 描述: 管理员登录
     * ============未完成=============
     * 1.IP异地校验
     *
     * @param loginDto
     * @return web.suzy.oj.pojo.vo.UserInfoVO
     * @date 2022/11/17 16:05
     * @auther YangSuzy
     **/
    public UserInfoVO login(LoginDTO loginDto) throws StatusFailException, StatusAccessDeniedException {
        //从Spring容器中获取HTTP请求对象和响应对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();

        //根据用户IP设置缓存Key，记录尝试登录次数
        String userIpAddr = IpUtils.getUserIpAddr(request);
        String key = Constants.Account.TRY_LOGIN_NUM.getCode() + loginDto.getUsername() + "_" + userIpAddr;
        Integer tryLoginCount = (Integer) redisUtils.get(key);
        //尝试登录次数过多锁定登录功能
        if (tryLoginCount != null && tryLoginCount >= 20) {
            throw new StatusFailException("对不起！登录失败次数过多！您的账号有风险，半个小时内暂时无法登录！");
        }

        //根据登录名获取用户角色信息视图对象
        SysUserRoleVO userRolesVo = userRoleEntityService.getUserRoles(null, loginDto.getUsername());

        if (userRolesVo == null) {
            throw new StatusFailException("用户名或密码错误");
        }
        if (!userRolesVo.getPassword().equals(SecureUtil.md5(loginDto.getPassword()))) {
            if (tryLoginCount == null) {
                //第一次登录失败设置计数缓存，30分钟不尝试该限制会自动清空消失
                redisUtils.set(key, 1, 60 * 30);
            } else {
                redisUtils.set(key, tryLoginCount + 1, 60 * 30);
            }
            throw new StatusFailException("用户名或密码错误");
        }
        if (userRolesVo.getStatus() != 0) {
            throw new StatusFailException("该账户已被封禁，请联系管理员进行处理！");
        }
        //认证成功，清除锁定限制
        if (tryLoginCount != null) {
            redisUtils.del(key);
        }
        //查询用户角色
        List<String> rolesList = new LinkedList<>();
        userRolesVo.getRoles().stream().forEach(role -> rolesList.add(role.getRole()));

        //判断用户是否为超级管理员、管理员或题目管理员
        if (rolesList.contains("admin") || rolesList.contains("root") || rolesList.contains("problem_admin")) {
            //获取用户登录凭证
            String jwt = jwtUtils.generateToken(userRolesVo.getUid());
            //放到信息头部
            response.setHeader("Authorization", jwt);
            response.setHeader("Access-Control-Expose-Headers", "Authorization");
            //保存用户登录会话记录
            sessionEntityService.save(new Session()
                    .setUid(userRolesVo.getUid())
                    .setIp(IpUtils.getUserIpAddr(request))
                    .setUserAgent(request.getHeader("User-Agent")));
            //返回用户信息对象
            UserInfoVO userInfoVo = new UserInfoVO();
            BeanUtil.copyProperties(userRolesVo, userInfoVo, "roles");
            userInfoVo.setRoleList(userRolesVo.getRoles().stream().map(SysRole::getRole).collect(Collectors.toList()));
            return userInfoVo;
        } else {
            throw new StatusAccessDeniedException("该账号并非管理员账号，无权登录！");
        }
    }

    /**
     * 方法名: logout
     * 描述: 管理员登出
     *
     * @return void
     * @date 2022/11/17 16:25
     * @auther YangSuzy
     **/
    public void logout() {
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        jwtUtils.cleanToken(userRolesVo.getUid());
        SecurityUtils.getSubject().logout();
    }
}
